﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace Gildor.SwapWin.Shell
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Main());

            var checkPoints = GetCheckPoints();

            Swap(checkPoints);
        }

        private static void Swap(Point[] checkpoints)
        {
            Func<int, int> getNext = p =>
            {
                p += GetRotateDirection();
                if(p == checkpoints.Length)
                {
                    return 0;
                }
                else if(p == -1)
                {
                    return checkpoints.Length - 1;
                }
                return p;
            };

            // Get all screens.
            var screens = checkpoints.Select(GetContainingScreen).ToArray();
            var workareas = screens.Select(p => p.WorkingArea).ToArray();
            var windows = checkpoints.Select(GetRootWindowUnderPos).ToArray();
            var rects = windows.Select(WinAPI.GetWindowRect).ToArray();

            for(int i = 0; i < checkpoints.Length; i++)
            {
                Log(i, "Processing: #");
                Log(WinAPI.GetWindowText(windows[i]), "Window Title: ");
                Log(WinAPI.GetProcessByWindow(windows[i]).ProcessName, "Process Name: ");
                Log(rects[i], "Original Rect: ");

                int j = getNext(i);
                var positionDelta = new Point(workareas[j].X - workareas[i].X, workareas[j].Y - workareas[i].Y);

                // Send window i to working area j.
                bool setWindowPosResult = WinAPI.SetWindowPos(windows[i],
                    WinAPI.HWND_TOP,
                    rects[i].X + positionDelta.X,
                    rects[i].Y + positionDelta.Y,
                    rects[i].Width, rects[i].Height,
                    WinAPI.SetWindowPosFlags.DoNotActivate |
                        WinAPI.SetWindowPosFlags.IgnoreZOrder |
                        WinAPI.SetWindowPosFlags.ShowWindow);

                Log(setWindowPosResult, "Set position result: ");

                bool setForegroundWindowResult = WinAPI.SetForegroundWindow(windows[i]);
                Log(setForegroundWindowResult, "Set foreground result: ");
            }
        }

        private static int GetRotateDirection()
        {
            return 1;
        }

        private static Point[] GetCheckPoints()
        {
            //TODO: This is a stub. Should get them from configuration.
            return new[]
            {
                GetSignificantPointOfRect(Screen.PrimaryScreen.WorkingArea),
                GetSignificantPointOfRect(Screen.AllScreens.First(p => !p.Primary).WorkingArea)
            };
        }

        private static IntPtr GetRootWindowUnderPos(Point pos)
        {
            return WinAPI.GetAncestor(WinAPI.WindowFromPoint(pos), WinAPI.GetAncestor_Flags.GetRootOwner);
        }

        private static Screen GetContainingScreen(Point point)
        {
            return Screen.AllScreens.First(p => p.Bounds.Contains(point));
        }

        private static Point GetSignificantPointOfRect(Rectangle rect)
        {
            return new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
        }

        private static void Log(object content, string category)
        {
            Debug.WriteLine(content, category);
        }
    }
}